package com.liuyusong.start;

import org.w3c.dom.css.RGBColor;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;

import static java.lang.Math.*;

public class Calculator extends JFrame implements ActionListener {
    //标识是负号还是正号 1正2负
    int flagSignal = 1;
    //创建面板，用于放置控件
    JPanel jPanel_North = new JPanel(new GridLayout(2,1,0,0));
    JPanel jPanel_South = new JPanel(new GridLayout(7,4,0,0));
    //jText1显示当前输入
    JTextField jText1 = new JTextField();
    //创建按钮，点击显示近五次结果
    JButton recent = new JButton();
    //创建列表，用于存放表达式
    Stack<String> postfixExpr = new Stack<>();
    //创建一个数组，用于存放结果
    String[] Results = new String[5];
    //左括号的数量
    int LeftBracketNum = 0;
    //右括号的数量
    int RightBracketNum = 0;
    //设置空的布局
    public Calculator(){
        //设置窗口标题
        this.setTitle(Const.TITLE);
        //设置窗口大小
        this.setSize(Const.FRAME_W,Const.FRAME_H);
        //设置窗口位置
        this.setLocation(Const.frame_x,Const.frame_y);
        //设置背景颜色
        this.getContentPane().setBackground(Color.BLACK);
        /*this.getContentPane().setBackground(new Color(253,231,195));*/
        //设置控件
        Init();
        //设置为不可拉伸
        this.setResizable(false);
        //设为可见
        this.setVisible(true);
        //关闭窗口时退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public void Init(){
        setTextBox();
        setButton();
    }
    //创建文本框
    public void setTextBox(){
        jPanel_North.setSize(new Dimension(300,100));
        //设置文本框的字体
        jText1.setFont(new Font("黑体",Font.BOLD,30));
        jText1.setBackground(new Color(254,233,180));

        recent.setBackground(Color.CYAN);
        recent.setText("最近五次结果");
        recent.addActionListener(this);
        //将文本框加入面板
        jPanel_North.add(jText1,BorderLayout.CENTER);
        jPanel_North.add(recent,BorderLayout.SOUTH);
        //将面板加入容器
        this.add(jPanel_North,BorderLayout.NORTH);
    }
    //创建按钮
    public void setButton(){
        jPanel_South.setSize(new Dimension(200,300));

        jPanel_South.setBackground(Color.CYAN);
        for(int i = 0;i<Const.CHARACTERS.length;i++){
            //创建按钮
            JButton btn = new JButton();
            //设置按钮的文字
            btn.setFont(new Font("黑体",Font.BOLD,20));
            btn.setForeground(new Color(102,204,255));
            btn.setBackground(new Color(248,187,87));
            btn.setText(Const.CHARACTERS[i]);
            //为按钮添加事件
            btn.addActionListener(this);
            //将按钮加入面板
            jPanel_South.add(btn);
        }
        //将面板加入容器
        this.add(jPanel_South,BorderLayout.CENTER);
    }
/***********************************************************/
    @Override
    public void actionPerformed(ActionEvent e) {
        //获取按钮信息
        String click = e.getActionCommand();
        if(click.equals("最近五次结果")){
            Result r = new Result(Results);
        }
        if(click.equals("("))
            LeftBracketNum ++;
        if (click.equals(")"))
            RightBracketNum ++;
        if(canSee(click)){
            postfixExpr.push(click);
        } else if (click.equals("±")) {
            if(postfixExpr.isEmpty())
                postfixExpr.push("negative");
            if(postfixExpr.peek().equals("positive")){
                postfixExpr.pop();
                postfixExpr.push("negative");
            }else if (postfixExpr.peek().equals("negative")){
                postfixExpr.pop();
                postfixExpr.push("positive");
            }   else{
                postfixExpr.push("negative");
            }
        } else if (click.equals("M+")){
            postfixExpr.push(Results[4]);
        } else if (click.equals("AC")) {
            resetStack(postfixExpr);
        } else if (click.equals("C")) {
            if(!postfixExpr.isEmpty())
                postfixExpr.pop();
        } else if (click.equals("=")) {
            //计算结果
            System.out.println("postfixExpr = "+postfixExpr);
            calculate();
            for (int i=0;i<4;i++)
                Results[i] = Results[i+1];
            Results[4] = postfixExpr.pop();
            jText1.setText(Results[4]);
            //清空
            clear();
            //在文本框中显示答案
            return;
        }
        jText1.setText(stackToStr());
    }
    //将栈置空
    public void resetStack(Stack stack){
        while(!stack.isEmpty())
            stack.pop();
    }
    //将栈转化为字符串
    public String stackToStr(){
        return postfixExpr.toString()
                .replaceAll("positive","+")
                .replaceAll("negative","-")
                .replace("[","")
                .replace("]","")
                .replace(",","")
                .replace(" ","");
    }
    //判断按钮的值是不是可显示的
    public boolean canSee(String s){
        for(String e:Const.VISUALABLECHAR)
            if(s.equals(e))
                return true;
        return false;
    }
    //测试
    public void test(){
        postfixExpr.push("2");
        postfixExpr.push("^");
        postfixExpr.push("9");
        postfixExpr.push("+");
        postfixExpr.push("9");
        postfixExpr.push("*");
        postfixExpr.push("(");
        postfixExpr.push("6");
        postfixExpr.push("-");
        postfixExpr.push("9");
        postfixExpr.push(")");
//        postfixExpr.push("+");
//        postfixExpr.push("1");
//        postfixExpr.push("5");
//        postfixExpr.push(")");
        calculate();
    }

    //计算结果
    public void calculate(){
        //先判断括号数量是否匹配
        if(RightBracketNum!=LeftBracketNum){
            clear();
            jText1.setText("括号数量不匹配！！！请重新输入");
            return;
        }
        //将算式转化为波兰表达式
        toPolish(postfixExpr);
        System.out.println("Polish :"+postfixExpr);
        //开始计算
        Stack<String> cache1 =new Stack<>();
        String str1 = "";
        String str2 = "";
        String str3 = "";
        try{
            while(!isNum(postfixExpr.getFirst())){
                System.out.println("------------");
                str1 = postfixExpr.pop();
                str2 = postfixExpr.peek();
                if(isSignal(str2)){
                    System.out.println("一");
                    signalOperator(cache1,str2,str1);
                }

                else {
                    System.out.println("二");
                    postfixExpr.pop();
                    str3 = postfixExpr.peek();
                    if(isDouble(str3)){
                        System.out.println("三");
                        doubleOperator(cache1,str3,str1,str2);
                    }else {
                        System.out.println("四");
                        cache1.push(str1);
                        postfixExpr.push(str2);
                    }
                }
                System.out.println("cache1 = "+cache1);
                System.out.println("postfixExpr = "+ postfixExpr);
                System.out.println("------------");
            }
        }catch(Exception e){
            System.out.println("《calculate》 is wrong !!!:"+e.getMessage()  );
        }
        System.out.println("计算结果："+postfixExpr.peek());
    }


    //单目运算符
    public boolean isSignal(String str){
        if(str.equals("positive")
                || str.equals("negative")
                || str.equals("Sin")
                || str.equals("Cos")
                || str.equals("CBK"))
            return true;
        else return false;
    }

    public void signalOperator(Stack<String> cache , String operator ,String num){
        switch (operator) {
            case "positive":System.out.println("is positive");
                postfixExpr.pop();
                            postfixExpr.push(num);
                            cacheToPostfixExpr(cache);return;
            case "negative":System.out.println("is negative");
                postfixExpr.pop();
                            postfixExpr.push(Double.toString(0-Double.parseDouble(num)));
                            cacheToPostfixExpr(cache);return;
            case "Sqrt":System.out.println("is Sqrt");
                postfixExpr.pop();
                        postfixExpr.push(Double.toString(Math.sqrt(Double.parseDouble(num))));
                        cacheToPostfixExpr(cache);return;
            case "CBK":System.out.println("is CBK");
                postfixExpr.pop();
                        postfixExpr.push(Double.toString(1/Double.parseDouble(num)));
                        cacheToPostfixExpr(cache);return;
            case "Sin":System.out.println("is Sin");
                postfixExpr.pop();
                        postfixExpr.push(Double.toString(Math.sin(Double.parseDouble(num))));
                        cacheToPostfixExpr(cache);return;
            case "Cos":System.out.println("is Cos");
                postfixExpr.pop();
                        postfixExpr.push(Double.toString(Math.cos(Double.parseDouble(num))));
                        cacheToPostfixExpr(cache);
        }
    }
    //双目运算符
    public boolean isDouble(String str){
        if (str.equals("+")
                ||str.equals("-")
                ||str.equals("*")
                ||str.equals("/")
                ||str.equals("%")
                ||str.equals("^"))
            return true;
        else return false;
    }
    public void doubleOperator(Stack<String> cache,String operator,String right,String left){
        switch (operator){
            case "+":postfixExpr.pop();
                System.out.println("is +");
                    postfixExpr.push(Double.toString(Double.parseDouble(left)+Double.parseDouble(right)));
                    cacheToPostfixExpr(cache);break;
            case "-":postfixExpr.pop();
                System.out.println("is -");
                postfixExpr.push(Double.toString(Double.parseDouble(left)-Double.parseDouble(right)));
                cacheToPostfixExpr(cache);break;
            case "*":postfixExpr.pop();
                System.out.println("is *");
                postfixExpr.push(Double.toString(Double.parseDouble(left)*Double.parseDouble(right)));
                cacheToPostfixExpr(cache);break;
            case "/":postfixExpr.pop();
                System.out.println("is /");
                postfixExpr.push(Double.toString(Double.parseDouble(left)/Double.parseDouble(right)));
                cacheToPostfixExpr(cache);break;
            case "%":postfixExpr.pop();
                System.out.println("is %");
                postfixExpr.push(Double.toString(Double.parseDouble(left)%Double.parseDouble(right)));
                cacheToPostfixExpr(cache);break;
            case "^":postfixExpr.pop();
                System.out.println("is ^");
                postfixExpr.push(Double.toString(Math.pow(Double.parseDouble(left),Double.parseDouble(right))));
                cacheToPostfixExpr(cache);
        }
    }
    //cache到postfixExpr
    public void cacheToPostfixExpr(Stack<String> cache){
        while(!cache.isEmpty())
            postfixExpr.push(cache.pop());
    }
    //转化为波兰表达式
    public void toPolish(Stack<String> stack){
        System.out.println("toPolish:");
        charToNumStr();
        System.out.println("原始数据:"+postfixExpr);
        Stack<String> cache1 = new Stack<>();
        Stack<String> cache2 = new Stack<>();
        while(!postfixExpr.isEmpty()){
            System.out.println("********");
            //cache1 为空，并且不是数字，直接入cache1
            if(cache1.isEmpty() && !isNum(postfixExpr.peek())){
                System.out.println("一");
                cache1.push(postfixExpr.pop());
            }//如果是右括号，则直接入cache1
            else if(postfixExpr.peek().contains(")")){
                System.out.println("二");
                cache1.push(postfixExpr.pop());
            }//如果是左括号，则将cache1出栈到cache2，直到发现右括号为止
            else if(postfixExpr.peek().contains("(")){
                System.out.println("三");
                postfixExpr.pop();
                while(!cache1.peek().contains(")")){
                    System.out.println("未找到)");
                    cache2.push(cache1.pop());
                }
                //将右括号出栈
                cache1.pop();
            }//数字直接入cache2
            else if (isNum(postfixExpr.peek())){
                System.out.println("四");
                System.out.println(postfixExpr.peek()+"入栈cache2");
                cache2.push(postfixExpr.pop());
            }//若优先级大于当前栈顶元素，则直接入栈cache2
            else if (priority(postfixExpr.peek())>=priority(cache1.peek())){
                System.out.println("五");
                cache1.push(postfixExpr.pop());
            }//否则则将cache1一直出栈到cache2 直到cache1的栈顶元素优先级小于当前元素，再将这个元素入栈cache1
            else if (priority(postfixExpr.peek())<priority(cache1.peek())){
                System.out.println("六");
                System.out.println("postfixExpr.peek()的优先级为："+priority(postfixExpr.peek()));
                System.out.println("cache1.peek()的优先级为："+priority(cache1.peek()));
                   while(!cache1.isEmpty() && priority(postfixExpr.peek()) < priority(cache1.peek())  )
                       cache2.push(cache1.pop());
                cache1.push(postfixExpr.pop());
            }
            System.out.println("cache1 :"+cache1);
            System.out.println("cache2 :"+ cache2);
            System.out.println("********");
        }
        System.out.println("toPlish while后cache2结果:"+cache2);
        //将元素归还postfixExpr
        while(!cache1.isEmpty())
            cache2.push(cache1.pop());
        while(!cache2.isEmpty())
            postfixExpr.push(cache2.pop());
    }
    //判断优先级
    public int priority(String str){
        switch (str){
            case "+":
            case "-":return 1;
            case "*":
            case "/":
            case "%":return 2;
            case "^":return 3;
            case "CBK":
            case "Sqrt":return 4;
            case "positive":
            case "negative":return 5;
        }
        return 0;
    }
    //将栈内的字符先进行处理，将数字合成一个字符串，再按原来的顺序入栈
    public void charToNumStr(){
        System.out.println("处理前："+postfixExpr);
        Stack<String> cache1 = new Stack<>();
        Stack<String> cache2 = new Stack<>();
        String c ;
        String str = "";
        while (!postfixExpr.isEmpty()){
            c = postfixExpr.pop();
            if(isNumber(c)){
                cache1.push(c);
            }else{
                while (!cache1.isEmpty()){
                    str += cache1.pop();
                }
                if(!str.equals(""))
                    cache2.push(str);
                cache2.push(c);
                str = "";
            }
        }
        str = "";
        while(!cache1.isEmpty())
            str += cache1.pop();
        if (!str.equals(""))
            cache2.push(str);
        while(!cache2.isEmpty()){
            postfixExpr.push(cache2.pop());
        }
        System.out.println("处理后："+postfixExpr);
    }
    //判断是不是数字字符
    public boolean isNumber(String s){
        for(String e:Const.NUMBER)
            if (s.contains(e)){
                return true;
            }
        return false;
    }
    //判断是不是数字
    public boolean isNum(String s){
        for(String e:Const.NUMBER)
            if(s.contains(e))
                return true;
        return false;
    }
    //判断是不是操作符
    public boolean isOperator(String s){
        for(String e:Const.OPERATOR)
            if(e.equals(s))
                return true;
        return false;
    }
    //将所有数据清空
    public void clear() {
        RightBracketNum = LeftBracketNum = 0;
        flagSignal = 0;
        resetStack(postfixExpr);
    }
}
